using System;
using System.Runtime.InteropServices;
using System.Runtime.InteropServices.ComTypes;
using System.IO;

namespace IfacesEnumsStructsClasses
{
    public class IStreamFromNativeStream : IStream
    {

        // Fields
        protected Stream dataStream;
        private long virtualPosition = -1L;

        public IStreamFromNativeStream(Stream nativestream)
        {
            if (nativestream == null)
            {
                throw new ArgumentNullException("nativestream");
            }
            this.dataStream = nativestream;
        }

        private void ActualizeVirtualPosition()
        {
            if (this.virtualPosition != -1L)
            {
                if (this.virtualPosition > this.dataStream.Length)
                {
                    this.dataStream.SetLength(this.virtualPosition);
                }
                this.dataStream.Position = this.virtualPosition;
                this.virtualPosition = -1L;
            }
        }

        protected static ExternalException EFail(string msg)
        {
            ExternalException exception = new ExternalException(msg, -2147467259);
            throw exception;
        }

        #region IStream Members

        void IStream.Clone(out IStream ppstm)
        {
            ppstm = null;
        }

        void IStream.Commit(int grfCommitFlags)
        {
            this.dataStream.Flush();
            this.ActualizeVirtualPosition();
        }

        void IStream.CopyTo(IStream pstm, long cb, IntPtr pcbRead, IntPtr pcbWritten)
        {
            int num = 0x1000;
            IntPtr buf = Marshal.AllocHGlobal(num);
            if (buf == IntPtr.Zero)
            {
                throw new OutOfMemoryException();
            }
            long num2 = 0L;
            try
            {
                while (num2 < cb)
                {
                    int length = num;
                    if ((num2 + length) > cb)
                    {
                        length = (int)(cb - num2);
                    }
                    int len = this.Read(buf, length);
                    if (len == 0)
                    {
                        goto Label_006C;
                    }
                    if (pstm.Write(buf, len, pcbWritten) != len)
                    {
                        throw EFail("Wrote an incorrect number of bytes");
                    }
                    num2 += len;
                }
            }
            finally
            {
                Marshal.FreeHGlobal(buf);
            }
        Label_006C:
            if ((pcbRead != null) && (pcbRead.Length > 0))
            {
                pcbRead = new IntPtr(num2);
                pcbWritten = new IntPtr(num2);
            }
        }

        void IStream.LockRegion(long libOffset, long cb, int dwLockType)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        void IStream.Read(byte[] pv, int cb, IntPtr pcbRead)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        void IStream.Revert()
        {
            throw new Exception("The method or operation is not implemented.");
        }

        void IStream.Seek(long dlibMove, int dwOrigin, IntPtr plibNewPosition)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        void IStream.SetSize(long libNewSize)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        void IStream.Stat(out System.Runtime.InteropServices.ComTypes.STATSTG pstatstg, int grfStatFlag)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        void IStream.UnlockRegion(long libOffset, long cb, int dwLockType)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        void IStream.Write(byte[] pv, int cb, IntPtr pcbWritten)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        #endregion
    }
}
